package com.nulgame.bukkit.plugin;

import static org.mockito.Mockito.*;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.bukkit.entity.Player;

import com.nulgame.bukkit.plugin.model.ChatInfo;

import junit.framework.TestCase;

public class AntiSpamPluginTestCase extends TestCase {
	
	public void testAntiChatSpam() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, NoSuchFieldException{
		Class pluginClass = Class.forName("com.nulgame.bukkit.plugin.AntiSpamPlugin");
		Method antiChatSpamMethod = pluginClass.getDeclaredMethod("antiChatSpam", Player.class, String.class, Long.class);
		antiChatSpamMethod.setAccessible(true);
		Field numberOfChatFiled = (Field)pluginClass.getDeclaredField("m_numberOfChat");
		numberOfChatFiled.setAccessible(true);
		AntiSpamPlugin plugin = (AntiSpamPlugin) pluginClass.newInstance();
		
		//player1 chat
		Player player = mock(Player.class);
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat1", System.currentTimeMillis()));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).get("chat1").total, new Long(1));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).size(), 1);
		assertEquals(plugin.getRecentPlayerChatMap().size(), 1);
		assertEquals(1L, numberOfChatFiled.get(plugin));
		
		//player1 chat new 
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat2", System.currentTimeMillis()));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).get("chat2").total, new Long(1));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).size(), 2);
		assertEquals(plugin.getRecentPlayerChatMap().size(), 1);
		assertEquals(2L, numberOfChatFiled.get(plugin));
		
		//player2 chat
		player = mock(Player.class);
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2", System.currentTimeMillis()));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).get("chat player2").total, new Long(1));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).size(), 1);
		assertEquals(plugin.getRecentPlayerChatMap().size(), 2);
		assertEquals(3L, numberOfChatFiled.get(plugin));
		
		//player2 chat new
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2 2", System.currentTimeMillis()));
		assertEquals(new Long(1), plugin.getRecentPlayerChatMap().get(player).get("chat player2 2").total);
		assertEquals(2, plugin.getRecentPlayerChatMap().get(player).size());
		assertEquals(2, plugin.getRecentPlayerChatMap().size());
		assertEquals(4L, numberOfChatFiled.get(plugin));
		
	}
	
	public void testAntiChatSpamWithViolation() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, InterruptedException, NoSuchFieldException{
		Class pluginClass = Class.forName("com.nulgame.bukkit.plugin.AntiSpamPlugin");
		Method antiChatSpamMethod = pluginClass.getDeclaredMethod("antiChatSpam", Player.class, String.class, Long.class);
		antiChatSpamMethod.setAccessible(true);
		Method initializeMethod  =  pluginClass.getDeclaredMethod("initialize");
		AntiSpamPlugin plugin = (AntiSpamPlugin) pluginClass.newInstance();
		initializeMethod.setAccessible(true);
		initializeMethod.invoke(plugin, null);
		antiChatSpamMethod.setAccessible(true);
		Field numberOfChatFiled = (Field)pluginClass.getDeclaredField("m_numberOfChat");
		numberOfChatFiled.setAccessible(true);
		//player1 chat
		Player player = mock(Player.class);
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat1", System.currentTimeMillis()));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).get("chat1").total, new Long(1));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).size(), 1);
		assertEquals(plugin.getRecentPlayerChatMap().size(), 1);
		assertEquals(1L, numberOfChatFiled.get(plugin));
		
		//player1 chat new 
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat2", System.currentTimeMillis()));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).get("chat2").total, new Long(1));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).size(), 2);
		assertEquals(plugin.getRecentPlayerChatMap().size(), 1);
		assertEquals(2L, numberOfChatFiled.get(plugin));
		
		//player2 chat
		player = mock(Player.class);
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2", System.currentTimeMillis()));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).get("chat player2").total, new Long(1));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).size(), 1);
		assertEquals(plugin.getRecentPlayerChatMap().size(), 2);
		assertEquals(3L, numberOfChatFiled.get(plugin));
		
		//player2 chat new
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2 2", System.currentTimeMillis()));
		assertEquals(new Long(1), plugin.getRecentPlayerChatMap().get(player).get("chat player2 2").total);
		assertEquals(2, plugin.getRecentPlayerChatMap().get(player).size());
		assertEquals(2, plugin.getRecentPlayerChatMap().size());
		assertEquals(4L, numberOfChatFiled.get(plugin));
		
		//player2 chat new
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2 2", System.currentTimeMillis()));
		assertEquals(new Long(2), plugin.getRecentPlayerChatMap().get(player).get("chat player2 2").total);
		assertEquals(2, plugin.getRecentPlayerChatMap().get(player).size());
		assertEquals(2, plugin.getRecentPlayerChatMap().size());
		assertEquals(5L, numberOfChatFiled.get(plugin));
		
		//player2 chat new
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2 2", System.currentTimeMillis()));
		assertEquals(new Long(3), plugin.getRecentPlayerChatMap().get(player).get("chat player2 2").total);
		assertEquals(2, plugin.getRecentPlayerChatMap().get(player).size());
		assertEquals(2, plugin.getRecentPlayerChatMap().size());
		assertEquals(6L, numberOfChatFiled.get(plugin));
		
		//player2 chat new
		assertFalse((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2 2", System.currentTimeMillis()));
		assertEquals(new Long(4), plugin.getRecentPlayerChatMap().get(player).get("chat player2 2").total);
		assertEquals(2, plugin.getRecentPlayerChatMap().get(player).size());
		assertEquals(2, plugin.getRecentPlayerChatMap().size());
		assertEquals(7L, numberOfChatFiled.get(plugin));
		
		//Have not violation
		//player1 chat
		player = mock(Player.class);
		plugin = (AntiSpamPlugin) pluginClass.newInstance();
		initializeMethod.invoke(plugin, null);
		
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat1", System.currentTimeMillis()));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).get("chat1").total, new Long(1));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).size(), 1);
		assertEquals(plugin.getRecentPlayerChatMap().size(), 1);
		assertEquals(1L, numberOfChatFiled.get(plugin));
		
		//player1 chat new 
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat2", System.currentTimeMillis()));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).get("chat2").total, new Long(1));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).size(), 2);
		assertEquals(plugin.getRecentPlayerChatMap().size(), 1);
		assertEquals(2L, numberOfChatFiled.get(plugin));
		
		//player2 chat
		player = mock(Player.class);
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2", System.currentTimeMillis()));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).get("chat player2").total, new Long(1));
		assertEquals(plugin.getRecentPlayerChatMap().get(player).size(), 1);
		assertEquals(plugin.getRecentPlayerChatMap().size(), 2);
		assertEquals(3L, numberOfChatFiled.get(plugin));
		
		//player2 chat new
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2 2", System.currentTimeMillis()));
		assertEquals(new Long(1), plugin.getRecentPlayerChatMap().get(player).get("chat player2 2").total);
		assertEquals(2, plugin.getRecentPlayerChatMap().get(player).size());
		assertEquals(2, plugin.getRecentPlayerChatMap().size());
		assertEquals(4L, numberOfChatFiled.get(plugin));
		
		//player2 chat new
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2 2", System.currentTimeMillis()));
		assertEquals(new Long(2), plugin.getRecentPlayerChatMap().get(player).get("chat player2 2").total);
		assertEquals(2, plugin.getRecentPlayerChatMap().get(player).size());
		assertEquals(2, plugin.getRecentPlayerChatMap().size());
		assertEquals(5L, numberOfChatFiled.get(plugin));
		
		//player2 chat new
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2 2", System.currentTimeMillis()));
		assertEquals(new Long(3), plugin.getRecentPlayerChatMap().get(player).get("chat player2 2").total);
		assertEquals(2, plugin.getRecentPlayerChatMap().get(player).size());
		assertEquals(2, plugin.getRecentPlayerChatMap().size());
		assertEquals(6L, numberOfChatFiled.get(plugin));
		Thread.sleep(20000);
		
		//player2 chat new
		assertTrue((Boolean)antiChatSpamMethod.invoke(plugin, player, "chat player2 2", System.currentTimeMillis()));
		assertEquals(new Long(1), plugin.getRecentPlayerChatMap().get(player).get("chat player2 2").total);
		assertEquals(2, plugin.getRecentPlayerChatMap().get(player).size());
		assertEquals(2, plugin.getRecentPlayerChatMap().size());
		assertEquals(4L, numberOfChatFiled.get(plugin));
	}
	
	public void testOnLeave() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, NoSuchFieldException{
		Class pluginClass = Class.forName("com.nulgame.bukkit.plugin.AntiSpamPlugin");
		AntiSpamPlugin plugin = (AntiSpamPlugin) pluginClass.newInstance();
		Player player = mock(Player.class);
		Map<Player, Map<String, ChatInfo>> recentPlayerChatMap = new HashMap<Player, Map<String, ChatInfo>>();
		recentPlayerChatMap.put(player,new HashMap<String, ChatInfo>());
		plugin.setRecentPlayerChatMap(recentPlayerChatMap);
		plugin.onLeave(player);
		assertNull(recentPlayerChatMap.get(player));
		
		player = mock(Player.class);
		recentPlayerChatMap.put(player, new HashMap<String, ChatInfo>());
		ChatInfo chatInfo =  new ChatInfo();
		chatInfo.total = 5L;
		Field numberOfChatFiled = (Field)pluginClass.getDeclaredField("m_numberOfChat");
		Field cleanedPlayerCandidateCriticalField = (Field)pluginClass.getDeclaredField("m_cleanedPlayerCandidateCritical");
		
		numberOfChatFiled.setAccessible(true);
		numberOfChatFiled.set(plugin, new Long(9));
		cleanedPlayerCandidateCriticalField.setAccessible(true);
		((Set<Player>)cleanedPlayerCandidateCriticalField.get(plugin)).add(player);
		
		recentPlayerChatMap.get(player).put("abc", chatInfo);
		plugin.onLeave(player);
		assertNull(recentPlayerChatMap.get(player));
		assertEquals(8L, numberOfChatFiled.get(plugin));
		assertTrue(((Set<Player>)cleanedPlayerCandidateCriticalField.get(plugin)).isEmpty());
	}
	
	public void testAntiChatOverFlow() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, InterruptedException{
		Class pluginClass = Class.forName("com.nulgame.bukkit.plugin.AntiSpamPlugin");
		AntiSpamPlugin plugin = (AntiSpamPlugin) pluginClass.newInstance();
		Method initializeMethod  =  pluginClass.getDeclaredMethod("initialize");
		initializeMethod.setAccessible(true);
		initializeMethod.invoke(plugin, null);
		Map<Player, Long> playerLastChatTime = new HashMap<Player, Long>();
		plugin.setPlayerLastTimeChat(playerLastChatTime);
		Method antiChatOverFlowMethod = pluginClass.getDeclaredMethod("antiChatOverFlow", Player.class, Long.class);
		antiChatOverFlowMethod.setAccessible(true);
		Player player = mock(Player.class);
		Player player2 = mock(Player.class);
		assertTrue((Boolean) antiChatOverFlowMethod.invoke(plugin, player, System.currentTimeMillis()));
		assertTrue((Boolean) antiChatOverFlowMethod.invoke(plugin, player2, System.currentTimeMillis()));
		assertFalse((Boolean) antiChatOverFlowMethod.invoke(plugin, player, System.currentTimeMillis()));
		
		Thread.sleep(1001L);
		long time = System.currentTimeMillis();
		assertTrue((Boolean) antiChatOverFlowMethod.invoke(plugin, player, time));
		Thread.sleep(1001L);
		time = System.currentTimeMillis();
		assertTrue((Boolean) antiChatOverFlowMethod.invoke(plugin, player, time));
	}
	
	public void testAntiIp() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
		Class pluginClass = Class.forName("com.nulgame.bukkit.plugin.AntiSpamPlugin");
		AntiSpamPlugin plugin = (AntiSpamPlugin) pluginClass.newInstance();
		Method antiIpMethod = plugin.getClass().getDeclaredMethod("antiIpAddress", String.class);
		antiIpMethod.setAccessible(true);
		assertEquals("192.169.0.1", antiIpMethod.invoke(plugin, "Here is my ip : 192.169.0.1"));
		assertEquals(null, antiIpMethod.invoke(plugin, "Here is my ip : 192.169.0.x"));
		assertEquals("192.169.0.9", antiIpMethod.invoke(plugin, "Here is my ip : 192.169.0.9:2005"));
	}
	
	public void testAntiWordCap() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
		Class pluginClass = Class.forName("com.nulgame.bukkit.plugin.AntiSpamPlugin");
		AntiSpamPlugin plugin = (AntiSpamPlugin) pluginClass.newInstance();
		Method antiWordCap = plugin.getClass().getDeclaredMethod("antiWordCap", String.class);
		antiWordCap.setAccessible(true);
		Method initializeMethod  =  pluginClass.getDeclaredMethod("initialize");
		initializeMethod.setAccessible(true);
		initializeMethod.invoke(plugin, null);
		assertFalse((Boolean)antiWordCap.invoke(plugin, "ABCDE"));
		assertTrue((Boolean)antiWordCap.invoke(plugin, "A b c d e"));
		assertTrue((Boolean)antiWordCap.invoke(plugin, ""));
	}
	
	public void testAntiWord() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
		Class pluginClass = Class.forName("com.nulgame.bukkit.plugin.AntiSpamPlugin");
		AntiSpamPlugin plugin = (AntiSpamPlugin) pluginClass.newInstance();
		Method antiWord = plugin.getClass().getDeclaredMethod("antiWord", String.class);
		antiWord.setAccessible(true);
		Method initializeMethod  =  pluginClass.getDeclaredMethod("initialize");
		initializeMethod.setAccessible(true);
		initializeMethod.invoke(plugin, null);
		assertNull(antiWord.invoke(plugin, "ABCDE"));
		assertEquals("abc",antiWord.invoke(plugin, "abc adsads"));
		assertEquals("xyz",antiWord.invoke(plugin, "asb xyz"));
		assertNull(antiWord.invoke(plugin, "asbxyz"));
		assertNull(antiWord.invoke(plugin, "abcxyz"));
	}
	
	public void testAntiServerAddress() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
		Class pluginClass = Class.forName("com.nulgame.bukkit.plugin.AntiSpamPlugin");
		AntiSpamPlugin plugin = (AntiSpamPlugin) pluginClass.newInstance();
		Method antiServerAddress = plugin.getClass().getDeclaredMethod("antiServerAddress", String.class);
		antiServerAddress.setAccessible(true);
		Method initializeMethod  =  pluginClass.getDeclaredMethod("initialize");
		initializeMethod.setAccessible(true);
		initializeMethod.invoke(plugin, null);
		assertNull(antiServerAddress.invoke(plugin, "ABCDE"));
		assertEquals("abc.com",antiServerAddress.invoke(plugin, "abc.com:123"));
		assertEquals("abc.com",antiServerAddress.invoke(plugin, "abc.com:1xy"));
		assertEquals("adsadsdsadsa.abc.net",antiServerAddress.invoke(plugin, "adsadsdsadsa.abc.net:123232"));
		assertNull(antiServerAddress.invoke(plugin, "abc.comz"));
	}
	
	public void testAntiChatWithReplacement() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
		Class pluginClass = Class.forName("com.nulgame.bukkit.plugin.AntiSpamPlugin");
		AntiSpamPlugin plugin = (AntiSpamPlugin) pluginClass.newInstance();
		Method replaceWord = plugin.getClass().getDeclaredMethod("replaceWord", String.class);
		replaceWord.setAccessible(true);
		Method initializeMethod  =  pluginClass.getDeclaredMethod("initialize");
		initializeMethod.setAccessible(true);
		initializeMethod.invoke(plugin, null);
		assertEquals("ABCDE",replaceWord.invoke(plugin, "ABCDE"));
		assertEquals("abc.com:123",replaceWord.invoke(plugin, "abc.com:123"));
		assertEquals("abc.com:1xy",replaceWord.invoke(plugin, "abc.com:1xy"));
		assertEquals("no",replaceWord.invoke(plugin, "nooo"));
		assertEquals("no",replaceWord.invoke(plugin, "noooooooooooooooooo"));
		assertEquals("no",replaceWord.invoke(plugin, "noooooooonoooooooooo"));
		assertEquals("a",replaceWord.invoke(plugin, "aaaaaaaaaaaaaaaa"));
		assertEquals("so why that no a",replaceWord.invoke(plugin, "so why that noooooooooooo aaaaaaaaa"));
		assertEquals("xyz",replaceWord.invoke(plugin, "xyyyyz"));
		assertEquals("no",replaceWord.invoke(plugin, "nonononono"));
	}
	
}
